package com.agua.enturno.db.util;

import com.agua.enturno.excepciones.ExcepcionDeReglaDelNegocio;
import com.agua.enturno.modelo.agenda.Agenda;
import com.agua.enturno.modelo.agenda.DiaNoLaboral;
import com.agua.enturno.modelo.agenda.JornadaLaboralHabitual;
import com.agua.enturno.modelo.prestador.PrestadorDeServicios;
import com.agua.enturno.modelo.prestador.Rubro;
import com.agua.enturno.modelo.prestador.Servicio;
import com.agua.enturno.modelo.roles.AdministradorDeAgenda;
import com.agua.enturno.modelo.roles.Cliente;
import com.agua.enturno.modelo.roles.Usuario;
import com.agua.enturno.persistencia.dao.*;
import com.agua.enturno.util.DayOfWeekTime;
import org.joda.time.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.agua.enturno.util.TestConstants.*;


public class PopuladorDeDatos {

	private static final String PROD_APPLICATION_CONTEXT = "applicationContext.xml";

	private RubroDAO rubroDAO;
	private UsuarioDAO usuarioDAO;
	private AgendaDAO agendaDAO;
	private PrestadorDeServiciosDAO prestadorDeServiciosDAO;
	private ServicioDAO servicioDAO;
	private JornadaLaboralHabitualDAO jornadaLaboralHabitualDAO;
	private DiaNoLaboralDAO diaNoLaboralDAO;
	
	private Map<String, Object> storedObjects = new HashMap<String, Object>();
	
	
	public static void main(String[] args) throws ExcepcionDeReglaDelNegocio {
		
		DateTimeUtils.setCurrentMillisFixed(LocalDate.now().withDayOfWeek(DateTimeConstants.MONDAY).toDateTimeAtStartOfDay().getMillis());
		
		PopuladorDeDatos populadorDeDatos = new PopuladorDeDatos();
		populadorDeDatos.ejecutar();
		
		DateTimeUtils.setCurrentMillisSystem();
	}
	
	private void ejecutar() throws ExcepcionDeReglaDelNegocio {
		
		inicializarDaos(PROD_APPLICATION_CONTEXT);
		
		popularUsuarios();
		asignarRolesAdmin();
		
		popularAgendas();
		popularJornadasHabituales();
		popularDiasNoLaborales();
		
		popularRubros();
		popularServicios();
		popularPrestadores();
	}
	
	private void inicializarDaos(String applicationContext) {
		
		ApplicationContext ctx = new ClassPathXmlApplicationContext(applicationContext);
		
		rubroDAO = (RubroDAO) ctx.getBean("rubroDAO");
		servicioDAO = (ServicioDAO) ctx.getBean("servicioDAO");
		agendaDAO = (AgendaDAO) ctx.getBean("agendaDAO");
		prestadorDeServiciosDAO = (PrestadorDeServiciosDAO) ctx.getBean("prestadorDeServiciosDAO");
		usuarioDAO = (UsuarioDAO) ctx.getBean("usuarioDAO");
		jornadaLaboralHabitualDAO = (JornadaLaboralHabitualDAO) ctx.getBean("jornadaLaboralHabitualDAO");
		diaNoLaboralDAO = (DiaNoLaboralDAO) ctx.getBean("diaNoLaboralDAO");
	}
	
	private void popularUsuarios() throws ExcepcionDeReglaDelNegocio {
		
		popularUsuario("Victor Del Rio",   "victor.delrio@gmail.com",    "123456");
		popularUsuario("Manuel Rodriguez", "manuel.rodriguez@gmail.com", "123456");
		popularUsuario("Juan Sanchez",     "juan.sanchez@gmail.com",     "123456");
		popularUsuario("Carlos Del Rio",   "carlos.delrio@gmail.com",    "123456");
		popularUsuario("German Ramirez",   "german.rodriguez@gmail.com", "123456");
		popularUsuario("Alejandra Lopez",  "alejandra.lopez@gmail.com",  "123456");
	}
	
	private void asignarRolesAdmin() throws ExcepcionDeReglaDelNegocio {
		
		asignarRolAdmin("German Ramirez");
		asignarRolAdmin("Alejandra Lopez");
		asignarRolAdmin("Carlos Del Rio");
		asignarRolAdmin("Victor Del Rio");
	}
	
	private void popularAgendas() throws ExcepcionDeReglaDelNegocio {
		
		popularAgenda("Dr. Ramirez", ANTELACION_60_DIAS, Arrays.asList((Usuario) storedObjects.get("German Ramirez")));
		popularAgenda("Dra. Lopez", ANTELACION_60_DIAS, Arrays.asList((Usuario) storedObjects.get("Alejandra Lopez")));
		popularAgenda("Dr. Del Rio", ANTELACION_60_DIAS, Arrays.asList((Usuario) storedObjects.get("Carlos Del Rio")));
		popularAgenda("Canchas", ANTELACION_60_DIAS, Arrays.asList((Usuario) storedObjects.get("Victor Del Rio")));
	}
	
	private void popularJornadasHabituales() throws ExcepcionDeReglaDelNegocio {
		
		popularJornadaHabitual((Agenda)storedObjects.get("Dr. Ramirez"), "lunes10a18_1", LUNES_A_LAS_10, LUNES_A_LAS_18, _1_HORA, _2_TURNOS);
		
		popularJornadaHabitual((Agenda)storedObjects.get("Dr. Del Rio"), "lunes10a18_2", LUNES_A_LAS_10, LUNES_A_LAS_18, _1_HORA, _2_TURNOS);
		popularJornadaHabitual((Agenda)storedObjects.get("Dr. Del Rio"), "martes930a1130", MARTES_A_LAS_10, MARTES_A_LAS_12, _20_MINUTOS, _1_TURNO);
		popularJornadaHabitual((Agenda)storedObjects.get("Dr. Del Rio"), "martes1430a1130", MARTES_A_LAS_14_30, MARTES_A_LAS_20_30, _1_30_HORAS, _2_TURNOS);
		popularJornadaHabitual((Agenda)storedObjects.get("Dr. Del Rio"), "miercoles10a18", MIERCOLES_A_LAS_10, MIERCOLES_A_LAS_18, _1_HORA, _1_TURNO);
		popularJornadaHabitual((Agenda)storedObjects.get("Dr. Del Rio"), "jueves10a18", JUEVES_A_LAS_10, JUEVES_A_LAS_18, _1_HORA, _1_TURNO);
		popularJornadaHabitual((Agenda)storedObjects.get("Dr. Del Rio"), "viernes10a18", VIERNES_A_LAS_10, VIERNES_A_LAS_18, _1_HORA, _2_TURNOS);
		popularJornadaHabitual((Agenda)storedObjects.get("Dr. Del Rio"), "sabados10a15", SABADO_A_LAS_10, SABADO_A_LAS_15, _1_HORA, _1_TURNO);
		
		popularJornadaHabitual((Agenda)storedObjects.get("Canchas"), "lunes9a18", LUNES_A_LAS_09, LUNES_A_LAS_18, _1_HORA, _3_TURNOS);
		popularJornadaHabitual((Agenda)storedObjects.get("Canchas"), "martes9a18", MARTES_A_LAS_09, MARTES_A_LAS_18, _1_HORA, _3_TURNOS);
		popularJornadaHabitual((Agenda)storedObjects.get("Canchas"), "miercoles9a18", MIERCOLES_A_LAS_09, MIERCOLES_A_LAS_18, _1_HORA, _3_TURNOS);
		popularJornadaHabitual((Agenda)storedObjects.get("Canchas"), "jueves9a18", JUEVES_A_LAS_09, JUEVES_A_LAS_18, _1_HORA, _3_TURNOS);
		popularJornadaHabitual((Agenda)storedObjects.get("Canchas"), "viernes9a18", VIERNES_A_LAS_09, VIERNES_A_LAS_18, _1_HORA, _3_TURNOS);
		popularJornadaHabitual((Agenda)storedObjects.get("Canchas"), "sabado9a13", SABADO_A_LAS_09, SABADO_A_LAS_13, _1_HORA, _3_TURNOS);
	}
	
	private void popularDiasNoLaborales() throws ExcepcionDeReglaDelNegocio {
		popularDiaNoLaboral((Agenda)storedObjects.get("Dr. Del Rio"), "diaConferencia", _29_DE_OCTUBRE_DEL_2013, "Décima conferencia de cardiología intervencionista");
	}
	
	private void popularRubros() {
		
		popularRubro("Salud");
		popularRubro("Deportes");
		popularRubro("Belleza");
		popularRubro("Trámites");
	}
	
	private void popularServicios() {
		
		popularServicio("Oftalmología", Arrays.asList((Agenda)storedObjects.get("Dr. Ramirez"), (Agenda)storedObjects.get("Dra. Lopez"), (Agenda)storedObjects.get("Dr. Del Rio")));
		popularServicio("Cardiología", Arrays.asList((Agenda)storedObjects.get("Dra. Lopez")));
		popularServicio("Canchas de futbol", Arrays.asList((Agenda)storedObjects.get("Canchas")));
	}
	
	private void popularPrestadores() throws ExcepcionDeReglaDelNegocio {
		
		Rubro rubroSalud = (Rubro) storedObjects.get("Salud");
		List<Servicio> serviciosConsultorio = Arrays.asList((Servicio)storedObjects.get("Oftalmología"), (Servicio)storedObjects.get("Cardiología"));
		List<Agenda> agendasConsultorio = Arrays.asList((Agenda)storedObjects.get("Dr. Ramirez"), (Agenda)storedObjects.get("Dra. Lopez"), (Agenda)storedObjects.get("Dr. Del Rio"));
		
		popularPrestador("Consultorio medico sur", "Aguilar 2547", "4785-0055", "/images/prestadores/prestador1.jpg", rubroSalud, serviciosConsultorio, agendasConsultorio);
		
		Rubro rubroDeportes = (Rubro) storedObjects.get("Deportes");
		List<Servicio> serviciosCanchas = Arrays.asList((Servicio)storedObjects.get("Canchas de futbol"));
		List<Agenda> agendasCanchas = Arrays.asList((Agenda)storedObjects.get("Canchas"));
		
		popularPrestador("Futbol 5 Mentarios", "Ciudad de la paz 355", "4867-7455", "/images/prestadores/prestador2.jpg", rubroDeportes, serviciosCanchas, agendasCanchas);
	}
	
	
	/*------------------------------------- Populadores ------------------------------------*/

	private void popularUsuario(String nombre, String email, String password) throws ExcepcionDeReglaDelNegocio {
		
		Usuario usuario = new Usuario(nombre, email, password);
		usuario.agregarRol(new Cliente());
		storedObjects.put(nombre, usuarioDAO.saveOrUpdate(usuario));
	}
	
	private void asignarRolAdmin(String nombreDeUsuario) throws ExcepcionDeReglaDelNegocio {
		
		Usuario usuario = (Usuario) storedObjects.get(nombreDeUsuario);
		usuario.agregarRol(new AdministradorDeAgenda());
		usuarioDAO.saveOrUpdate(usuario);
	}
	
	private void popularAgenda(String nombre, Period antelacionMaxima, List<Usuario> administradores) throws ExcepcionDeReglaDelNegocio {
		
		Agenda agenda = agendaDAO.saveOrUpdate(new Agenda(nombre, antelacionMaxima));
		
		for (Usuario usuario : administradores) {
			
			((AdministradorDeAgenda) usuario.getRol(AdministradorDeAgenda.NOMBRE_DE_ROL)).getAgendas().add(agenda);
			usuarioDAO.saveOrUpdate(usuario);
		}
		
		storedObjects.put(nombre, agenda);
	}
	
	private void popularJornadaHabitual(Agenda agenda, String nombre, DayOfWeekTime diaYHoraDeInicio, DayOfWeekTime diaYHoraDeFin, 
			Duration duracionDeLosTurnos, Integer vacantesPorTurno) throws ExcepcionDeReglaDelNegocio {
		
		JornadaLaboralHabitual jornadaHabitual = new JornadaLaboralHabitual(diaYHoraDeInicio, diaYHoraDeFin, duracionDeLosTurnos, vacantesPorTurno);
		agenda.agregarJornadaLaboralHabitual(jornadaHabitual);
		
		storedObjects.put(nombre, jornadaLaboralHabitualDAO.saveOrUpdate(jornadaHabitual));
	}	
	
	private void popularDiaNoLaboral(Agenda agenda, String nombre, LocalDate fecha, String motivo) throws ExcepcionDeReglaDelNegocio {
		
		DiaNoLaboral diaNoLaboral = new DiaNoLaboral(fecha, motivo);
		agenda.agregarDiaNoLaboral(diaNoLaboral);
		
		storedObjects.put(nombre, diaNoLaboralDAO.saveOrUpdate(diaNoLaboral));
	}
	
	private void popularRubro(String nombre) {
		
		Rubro rubro = new Rubro(nombre);
		storedObjects.put(nombre, rubroDAO.saveOrUpdate(rubro));
	}
	
	private void popularServicio(String nombre, List<Agenda> agendas) {
		
		Servicio servicio = new Servicio(nombre);
		
		for (Agenda agenda : agendas) 
			servicio.getAgendas().add(agenda);
		
		storedObjects.put(nombre, servicioDAO.saveOrUpdate(servicio));
	}
	
	private void popularPrestador(String nombre, String direccion, String telefono, String imagen, Rubro rubro, 
			List<Servicio> servicios, List<Agenda> agendas) throws ExcepcionDeReglaDelNegocio {
		
		PrestadorDeServicios prestador = new PrestadorDeServicios(nombre, direccion, telefono, imagen);
		
		rubro.agregarPrestadorDeServicios(prestador);
		
		for (Servicio servicio : servicios) 
			prestador.agregarServicio(servicio);
		
		for (Agenda agenda : agendas) 
			prestador.agregarAgenda(agenda);
		
		storedObjects.put(nombre, prestadorDeServiciosDAO.saveOrUpdate(prestador));
	}
	
	/*--------------------------------------------------------------------------------------*/
	
}
